package com.springboot.test.service;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.springboot.test.common.enums.ErrorCode;
import com.springboot.test.common.enums.GoodsStatus;
import com.springboot.test.common.enums.MessageTypeEnum;
import com.springboot.test.common.exception.BizException;
import com.springboot.test.common.utils.ConvertUtils;
import com.springboot.test.common.utils.DateTimeUtil;
import com.springboot.test.common.utils.IdGenerator;
import com.springboot.test.entity.*;
import com.springboot.test.entity.mapper.GoodsMapper;
import com.springboot.test.service.param.AddGoodsParam;
import com.springboot.test.service.param.GoodsPageParam;
import com.springboot.test.service.param.UpdateGoodsParam;
import com.springboot.test.service.param.pageparam.BasePageParam;
import com.springboot.test.service.result.GoodsDetailResult;
import com.springboot.test.service.result.GoodsPageResult;
import com.springboot.test.service.result.MyGoodsResult;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

@Service
public class GoodsService extends ServiceImpl<GoodsMapper, GoodsEntity> {

    @Resource
    private UserService userService;

    @Resource
    private GoodsTypeService goodsTypeService;

    @Resource
    private GoodsDetailService goodsDetailService;

    @Resource
    private MessageService messageService;

    @Resource
    private UnAuditReasonService unAuditReasonService;


    public Page<GoodsPageResult> goodsPage(GoodsPageParam param,Integer type) {
        List<String> userCodes = new ArrayList<>();
        if(StringUtils.isNotBlank(param.getUserName())){
            List<UserEntity> list = userService.listByUserName(param.getUserName());
            userCodes = list.stream().map(UserEntity::getUserId).collect(Collectors.toList());
        }
        Page<GoodsEntity> page = page(new Page<>(param.getPageNum(), param.getPageSize()), new QueryWrapper<GoodsEntity>().lambda()
                .eq(type.equals(0),GoodsEntity::getStatus,GoodsStatus.PUBLISH.getCode())
                .eq(StringUtils.isNotBlank(param.getGoodsParentCode()), GoodsEntity::getGoodsParentTypeCode, param.getGoodsParentCode())
                .eq(StringUtils.isNotBlank(param.getGoodsTypeCode()), GoodsEntity::getGoodsTypeCode, param.getGoodsTypeCode())
                .eq(param.getStatus()!=null,GoodsEntity::getStatus,param.getStatus())
                .like(StringUtils.isNotBlank(param.getGoodsCode()),GoodsEntity::getGoodsCode,param.getGoodsCode())
                .in(!CollectionUtils.isEmpty(userCodes),GoodsEntity::getPublishUserCode,userCodes)
                .and(StringUtils.isNotBlank(param.getKeyWord()), i -> i.like(GoodsEntity::getGoodsName, param.getKeyWord())
                        .or().like(GoodsEntity::getGoodsParentType, param.getKeyWord())
                        .or().like(GoodsEntity::getGoodsType, param.getKeyWord())
                )
                .orderByDesc(GoodsEntity::getCreateTime)
        );
        List<GoodsEntity> records = page.getRecords();
        if(CollectionUtils.isEmpty(records)){
            return new Page<>(param.getPageNum(),param.getPageSize());
        }
        List<GoodsPageResult> resultList = convertListToResult(records);
        Page<GoodsPageResult> pageResultPage = new Page<>();
        pageResultPage.setCurrent(page.getCurrent());
        pageResultPage.setSize(page.getSize());
        pageResultPage.setTotal(page.getTotal());
        pageResultPage.setRecords(resultList);
        return pageResultPage;
    }


    @Transactional(rollbackFor = Exception.class)
    public Boolean addGoods(AddGoodsParam param,String userCode){
        GoodsEntity goodsEntity = new GoodsEntity();
        goodsEntity.setGoodsCode(IdGenerator.getNewId("G"));
        goodsEntity.setPublishUserCode(userCode);
        setGoodsEntity(goodsEntity, param.getGoodsName(), param.getGoodsTypeCode(), param.getParentTypeCode(), param.getIndexImg());
        goodsEntity.setPublish(1);
        goodsEntity.setTrade(1);
        goodsEntity.setPrice(param.getPrice());
        GoodsDetailEntity goodsDetailEntity = new GoodsDetailEntity();
        goodsDetailEntity.setGoodsCode(goodsEntity.getGoodsCode());
        goodsDetailEntity.setGoodsSpec(param.getSpec());
        goodsDetailEntity.setGoodsImgList(JSONObject.toJSONString(param.getImgList()));
        goodsDetailEntity.setIntro(param.getIntro());
        save(goodsEntity);
        goodsDetailService.save(goodsDetailEntity);
        messageService.sendMessage(userCode,goodsEntity.getGoodsCode(), MessageTypeEnum.PUBLISH.getCode(),goodsEntity.getGoodsName(),"");
        return true;
    }

    public GoodsDetailResult detailByCode(String goodsCode){
        GoodsEntity goodsEntity = queryOneByCode(goodsCode);
        if(goodsEntity==null){
            return new GoodsDetailResult();
        }
        GoodsDetailEntity detailEntity = goodsDetailService.getOne(new QueryWrapper<GoodsDetailEntity>().lambda().eq(GoodsDetailEntity::getGoodsCode, goodsCode));
        GoodsDetailResult goodsDetailResult = ConvertUtils.convert(goodsEntity,GoodsDetailResult.class);
        UserEntity userEntity = userService.queryOneByCode(goodsEntity.getPublishUserCode());
        goodsDetailResult.setSpec(detailEntity.getGoodsSpec());
        goodsDetailResult.setImgList(JSONObject.parseArray(detailEntity.getGoodsImgList(),String.class));
        goodsDetailResult.setIntro(detailEntity.getIntro());
        if(userEntity != null){
            goodsDetailResult.setNickName(userEntity.getNickName());
            goodsDetailResult.setEmail(userEntity.getEmail());
            goodsDetailResult.setPhone(userEntity.getPhone());
        }else {
            goodsDetailResult.setNickName("用户已删除，请联系管理员");
            goodsDetailResult.setPhone("");
        }

        return goodsDetailResult;
    }

    public Page<MyGoodsResult> myGoodsResultPage(BasePageParam basePageParam,String userCode){
        Page<GoodsEntity> page = page(new Page<>(basePageParam.getPageNum(), basePageParam.getPageSize()), new QueryWrapper<GoodsEntity>().lambda()
                .eq(GoodsEntity::getPublishUserCode, userCode)
                .orderByDesc(GoodsEntity::getCreateTime)
        );
        if(page.getRecords().isEmpty()){
            return new Page<>(basePageParam.getPageNum(), basePageParam.getPageSize());
        }
        List<GoodsEntity> records = page.getRecords();
        List<MyGoodsResult> myGoodsResults = new ArrayList<>();
        for (GoodsEntity record : records) {
            MyGoodsResult myGoodsResult = ConvertUtils.convert(record,MyGoodsResult.class);
            myGoodsResult.setCreateTime(DateTimeUtil.dateToStr(record.getCreateTime()));
            if(record.getPublishTime() != null){
                myGoodsResult.setPublishTime(DateTimeUtil.dateToStr(record.getPublishTime()));
            }
            GoodsStatus goodsStatus = GoodsStatus.getByCode(record.getStatus());
            myGoodsResult.setStatusInfo(goodsStatus.getDescribe());
            myGoodsResults.add(myGoodsResult);
        }
        Page<MyGoodsResult> pageResultPage = new Page<>();
        pageResultPage.setCurrent(page.getCurrent());
        pageResultPage.setSize(page.getSize());
        pageResultPage.setTotal(page.getTotal());
        pageResultPage.setRecords(myGoodsResults);
        return pageResultPage;
    }

    public List<GoodsPageResult> listByGoodsCodes(Collection<String> goodsCodes){
        if(CollectionUtils.isEmpty(goodsCodes)){
            throw new BizException(ErrorCode.ERROR);
        }
        List<GoodsEntity> entityList = list(new QueryWrapper<GoodsEntity>().lambda().in(GoodsEntity::getGoodsCode,goodsCodes));
        return convertListToResult(entityList);
    }

    private List<GoodsPageResult> convertListToResult(List<GoodsEntity> records){
        List<GoodsPageResult> resultList = new ArrayList<>();
        List<String> userCodes = records.stream().map(GoodsEntity::getPublishUserCode).collect(Collectors.toList());
        List<UserEntity> userEntities = userService.listByUserCodes(userCodes);
        Map<String, UserEntity> userEntityMap = userEntities.stream().collect(Collectors.toMap(UserEntity::getUserId, a -> a));
        records.forEach(a->{
            GoodsPageResult goodsPageResult = ConvertUtils.convert(a,GoodsPageResult.class);
            if(userEntityMap.get(a.getPublishUserCode())!= null){
                UserEntity userEntity = userEntityMap.get(a.getPublishUserCode());
                goodsPageResult.setAvatar(userEntity.getAvatar());
                goodsPageResult.setUserName(userEntity.getNickName());
            }else {
                goodsPageResult.setUserName("未知用户");
                goodsPageResult.setAvatar("https://nbut-business.oss-cn-hangzhou.aliyuncs.com/12c954518bb74edf841ca50a3e55d349013394d9e91a0f27d7c2090df4cf437c.jpeg");
            }
            resultList.add(goodsPageResult);
        });
        return resultList;
    }


    public Boolean updateStatus(String goodsCode, Integer status) {
        GoodsEntity goodsEntity = queryOneByCode(goodsCode);
        if (goodsEntity == null){
            return Boolean.FALSE;
        }
        GoodsStatus goodsStatus = GoodsStatus.getByCode(status);
        if(goodsStatus == null){
            return Boolean.FALSE;
        }
        switch (goodsStatus){
            case PUBLISH:
                goodsEntity.setPublish(0);
                goodsEntity.setPublishTime(new Date());
                if(GoodsStatus.AUDIT.getCode().equals(goodsEntity.getStatus())){
                    messageService.sendMessage(goodsEntity.getPublishUserCode(),goodsCode,MessageTypeEnum.AUDIT.getCode(),goodsEntity.getGoodsName(),"");
                }else{
                    messageService.sendMessage(goodsEntity.getPublishUserCode(),goodsCode,MessageTypeEnum.RE_PUBLISH.getCode(),goodsEntity.getGoodsName(),"");
                }
                break;
            case NO_PUBLISH:
                goodsEntity.setPublish(2);
                messageService.sendMessage(goodsEntity.getPublishUserCode(),goodsCode,MessageTypeEnum.UN_PUBLISH.getCode(),goodsEntity.getGoodsName(),"");
                break;
            case TRADE:
                goodsEntity.setTrade(0);
                messageService.sendMessage(goodsEntity.getPublishUserCode(),goodsCode,MessageTypeEnum.TRADE.getCode(),goodsEntity.getGoodsName(),"");
                break;
            case NO_AUDIT:
                messageService.sendMessage(goodsEntity.getPublishUserCode(),goodsCode,MessageTypeEnum.UN_AUDIT.getCode(),goodsEntity.getGoodsName(),"");
                break;
        }
        goodsEntity.setStatus(status);
        return updateById(goodsEntity);
    }

    public GoodsEntity queryOneByCode(String goodsCode){
        return getOne(new QueryWrapper<GoodsEntity>().lambda().eq(GoodsEntity::getGoodsCode, goodsCode));
    }

    @Transactional
    public Boolean updateGoods(UpdateGoodsParam param) {
        GoodsEntity goodsEntity = queryOneByCode(param.getGoodsCode());
        if(goodsEntity != null){
            setGoodsEntity(goodsEntity, param.getGoodsName(), param.getGoodsTypeCode(), param.getParentTypeCode(), param.getIndexImg());
            goodsEntity.setPrice(param.getPrice());
            goodsEntity.setPublish(1);
            goodsEntity.setStatus(GoodsStatus.AUDIT.getCode());
            GoodsDetailEntity goodsDetailEntity = goodsDetailService.getOne(new QueryWrapper<GoodsDetailEntity>().lambda().eq(GoodsDetailEntity::getGoodsCode, param.getGoodsCode()));
            goodsDetailEntity.setIntro(param.getIntro());
            goodsDetailEntity.setGoodsSpec(param.getSpec());
            goodsDetailEntity.setGoodsImgList(JSONObject.toJSONString(param.getImgList()));
            updateById(goodsEntity);
            goodsDetailService.updateById(goodsDetailEntity);
            messageService.sendMessage(goodsEntity.getPublishUserCode(),param.getGoodsCode(),MessageTypeEnum.PUBLISH.getCode(),goodsEntity.getGoodsName(),"");
            return Boolean.TRUE;
        }
        throw new BizException("商品编号错误");
    }

    private void setGoodsEntity(GoodsEntity goodsEntity, String goodsName, String goodsTypeCode, String parentTypeCode, String indexImg) {
        goodsEntity.setGoodsName(goodsName);
        GoodsTypeEntity goodsTypeEntity = goodsTypeService.getOneByCode(goodsTypeCode);
        if(goodsTypeEntity != null){
            goodsEntity.setGoodsType(goodsTypeEntity.getGoodsType());
            goodsEntity.setGoodsTypeCode(goodsTypeCode);
        }else {
            throw new BizException("商品分类错误");
        }
        GoodsTypeEntity goodsParentTypeEntity = goodsTypeService.getOneByCode(parentTypeCode);
        if(goodsParentTypeEntity != null){
            goodsEntity.setGoodsParentType(goodsParentTypeEntity.getGoodsType());
            goodsEntity.setGoodsParentTypeCode(parentTypeCode);
        }else {
            throw new BizException("商品分类错误");
        }
        goodsEntity.setIndexImg(indexImg);
    }

    public Boolean adminUpdateStatus(String goodsCode,Integer status,String reason) {
        GoodsEntity goodsEntity = queryOneByCode(goodsCode);
        if(goodsEntity.getStatus()==0&&GoodsStatus.NO_AUDIT.getCode().equals(status)){
            UnAuditReasonEntity unAuditReasonEntity = unAuditReasonService.getOne(new QueryWrapper<UnAuditReasonEntity>()
                    .lambda().eq(UnAuditReasonEntity::getGoodsCode,goodsCode));
            if(unAuditReasonEntity==null){
                unAuditReasonEntity = new UnAuditReasonEntity();
                unAuditReasonEntity.setReasonCode(IdGenerator.getNewId("R"));
            }
            unAuditReasonEntity.setUnAuditReason(reason);
            unAuditReasonEntity.setGoodsCode(goodsCode);
            unAuditReasonEntity.setUserCode(goodsEntity.getPublishUserCode());
            unAuditReasonService.saveOrUpdate(unAuditReasonEntity);
        }
        updateStatus(goodsCode,status);
        return Boolean.TRUE;
    }

    public BigDecimal tradeNumber(){
        GoodsEntity goodsEntity = getOne(new QueryWrapper<GoodsEntity>().eq("status", 3).select("sum(price) as price"));
        if(goodsEntity==null){
            return BigDecimal.ZERO;
        }
        return goodsEntity.getPrice();
    }

    public Integer tradeCount(){
        return count(new QueryWrapper<GoodsEntity>().eq("status", 3));
    }
}
